package com.isoftstone.securityframework.device.local;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.isoftstone.securityframework.api.Permission;
import com.isoftstone.securityframework.api.factory.ManagerFactory;
import com.isoftstone.securityframework.auth.realm.DefaultAuthRealm;
import com.isoftstone.securityframework.auth.realm.SubjectPermissionRealm;
import com.isoftstone.securityframework.auth.realm.SubjectRealm;
import com.isoftstone.securityframework.device.Device;
import com.isoftstone.securityframework.device.auth.DeviceAuthenticationInfo;
import com.isoftstone.securityframework.device.exception.DeviceException;
import com.isoftstone.securityframework.device.exception.UnknowDeviceException;
import com.isoftstone.securityframework.device.subject.DeviceToken;
/**
 * Device认证/鉴权实现
 * @author david
 *
 */
public class DeviceAuthRealm extends DefaultAuthRealm {

	private static final Logger logger = LoggerFactory.getLogger(DeviceAuthRealm.class);
	
	
	public DeviceAuthRealm() {
		super();
		this.setAuthenticationTokenClass(DeviceToken.class);
	}

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        if (principals == null) {
            throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
        }
//        String deviceId = ((Device) getAvailablePrincipal(principals)).getDeviceFlag();
        try {
//        	
//        	
//        	
//			Thread.currentThread().setContextClassLoader(DeviceManagerLocalImpl.class.getClassLoader());
//        	SubjectRealm subjectRealm = this.buildSubjectRealm(factory);
//        	Thread.currentThread().setContextClassLoader(old);
//
//        	if(subjectRealm==null){
//        		throw new Exception("subjectRealm is null!");
//        	}
//        	Device device = (Device) subjectRealm.getSubject(deviceId);
        	
        	
        	Device device = (Device) getAvailablePrincipal(principals);
        	
        	ClassLoader old = Thread.currentThread().getContextClassLoader();
			Thread.currentThread().setContextClassLoader(Class.forName(this.getConfig().getSectionProperty("realms", "factory")).getClassLoader());
        	ManagerFactory factory = this.buildManagerFactory();
        	
			Thread.currentThread().setContextClassLoader(DevicePermissionRealm.class.getClassLoader());
        	SubjectPermissionRealm[] subjectPermissionRealms = this.buildSubjectPermissionRealms(factory);
        	Thread.currentThread().setContextClassLoader(old);

        	if(subjectPermissionRealms==null || 0==subjectPermissionRealms.length){
        		logger.warn("No subjectPermissionRealm register,subject permission unknow!");
        	}
        	
        	List<Permission> allPermission = new ArrayList<Permission>();
    		for (SubjectPermissionRealm s : subjectPermissionRealms) {
				allPermission.addAll(s.getSubjectPermission(device));
			}

            Set<String> permissions = new HashSet<String>();
        	for (Permission p : allPermission) {
    			permissions.add(p.getPermissionName().toString());
    		}

        	 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
             info.setStringPermissions(permissions);
             return info;
		} catch (Exception e) {
            throw new AuthorizationException(e);
		}
	}
	
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		DeviceToken t = (DeviceToken) token;
		String deviceId = t.getDeviceFlag();
		if(deviceId==null){
            throw new DeviceException("Null device are not allowed by this realm.");
		}
		try {

			ClassLoader old = Thread.currentThread().getContextClassLoader();
			Thread.currentThread().setContextClassLoader(Class.forName(this.getConfig().getSectionProperty("realms", "factory")).getClassLoader());
        	ManagerFactory factory = this.buildManagerFactory();
        	
        	
			Thread.currentThread().setContextClassLoader(DeviceManagerLocalImpl.class.getClassLoader());
			SubjectRealm subjectRealm = this.buildSubjectRealm(factory);
			Thread.currentThread().setContextClassLoader(old);
			Device device = (Device) subjectRealm.getSubject(deviceId);
			if(device == null){
				throw new UnknowDeviceException(String.format("No device found for device [%s]",deviceId));
			}
			subjectRealm.recordLogin(device);
			DeviceAuthenticationInfo info = new DeviceAuthenticationInfo(device, getName());
			return info;
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}


}
